/**
 * Генеалогическое дерево.
 * Содержит данные о родственниках конкретного человека.
 * Данный человек формально является корнем данного дерева.
 */

#ifndef _GENEALOGYTREE_H
#define	_GENEALOGYTREE_H

#include <list>
#include "common/NullPointerException.h"
#include "tree/Tree.h"
#include "tree/TreeIterator.h"
#include "Person.h"
#include "GenealogyTreeException.h"
#include "conf.h"

namespace etu {
namespace genealogy_tree {

using etu::common::NullPointerException;
using etu::tree::Tree;
using etu::tree::TreeIterator;

class GenealogyTreeXmlWriter;

class GenealogyTree {

    Tree<const Person *> tree;

public:
    /**
     * Создание пустого дерева
     */
    GenealogyTree();

    /**
     * Конструктор копии.
     * В процессе копирования объект дерева будет клонирован (deep copy).
     */
    GenealogyTree(const GenealogyTree& orig);

    /**
     * Удаление объекта.
     * Данные обо всех родственниках также будут удалены.
     */
    virtual ~GenealogyTree();

    /**
     * Задание корня дерева, то есть человека,
     * для которого предполагается строить его генеалогическое дерево.
     * Если корень уже был задан ранее,
     * то данные о нём и всех его родственниках будут удалены
     * (то есть соответствует операции очистки содержимого дерева).
     * @param root данные о человеке, для которого предполагается строить дерево
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual void setRoot(const Person* root) throw(NullPointerException);

    /**
     * Получение корня дерева
     * @return корень дерева
     * @throws GenealogyTreeException если дерево пустое (то есть данные о корне не заданы)
     */
    virtual const Person* getRoot() const throw(GenealogyTreeException);

    /**
     * Проверка дерева на пустоту
     * @return true, если дерево пустое; иначе false
     */
    virtual bool isEmpty() const;

    /**
     * Получение количества людей, данные о которых содержатся в дереве
     * @return количество элементов в дереве
     */
    virtual int getSize() const;

    /**
     * Проверка, содержит ли дерево данные о заданном человеке
     * @param person данные о человеке
     * @return true, если данные о человеке содержатся в дереве; иначе false
     * @throws NullPointerException если данные о человеке на заданы
     */
    virtual bool contains(const Person* person) const
        throw(NullPointerException);

    /**
     * Проверка, содержатся ли в дереве данные о матери заданного человека
     * @param person данные о человеке
     * @return true, если данные о матери содержатся в дереве; иначе false
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual bool hasMother(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Проверка, содержатся ли в дереве данные об отце заданного человека
     * @param person данные о человеке
     * @return true, если данные об отце содержатся в дереве; иначе false
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual bool hasFather(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Получение данные о матери заданного человека
     * @param person данные о человеке
     * @return данные о материи заданного человека
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве;
     * если данные о матери заданного человека не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual const Person* getMother(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Получение данных об отце заданного человека
     * @param person данные о человеке
     * @return данные об отце заданного человека
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве;
     * если данные об отце данного человека не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual const Person* getFather(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Добавление данных о матери заданного человека.
     * Если такие данные уже содержится, то они будет удалены.
     * @param person данные о человеке
     * @param mother данные о матери человека
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве;
     * если дата рождения заданного человека раньше, чем дата рождения его матери;
     * если дата смерти матери раньше, чем дата рождения человека;
     * если пол матери не является женским
     * @throws NullPointerException если данные о человеке на заданы;
     * если данные о матери человека не заданы
     */
    virtual void setMother(const Person* person, const Person* mother)
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Добавление данных об отце заданного человека.
     * Если такие данные уже содержится, то они будет удалены.
     * @param person данные о человеке
     * @param father данные об отце человека
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве;
     * если дата рождения заданного человека раньше, чем дата рождения его отца;
     * если пол отца не является мужским
     * @throws NullPointerException если данные о человеке на заданы;
     * если данные об отце человека не заданы
     */
    virtual void setFather(const Person* person, const Person* father)
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Проверка, содержатся ли в дереве данные о детях заданного человека
     * @param person данные о человеке
     * @return true, если данные о детях заданного человека содержатся в дереве; иначе false
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual bool hasChilds(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Добавление данных о ребёнке заданного человека
     * @param parent данные о родителе ребёнка
     * @param child данные о ребёнке
     * @throws GenealogyTreeException если данные о родителе не содержатся в дереве
     * @throws NullPointerException если не заданы данные о ребёнке или родителе
     */
    virtual void addChild(const Person* parent, const Person* child)
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Удаление данных о заданном человеке. Данные о его родственниках,
     * на которых больше никто не ссылается в дереве, также будут удалены.
     * @param person данные об удаляемом человеке
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual void remove(const Person* person)
        throw(GenealogyTreeException, NullPointerException);

    /**
     * Получение данных о детях заданного человека
     * @param person данные о человеке
     * @return список данных о детях заданного человека
     * @throws GenealogyTreeException если данные о человеке не содержатся в дереве
     * @throws NullPointerException если данные о человеке не заданы
     */
    virtual std::list<const Person *>* getChilds(const Person* person) const
        throw(GenealogyTreeException, NullPointerException);

    bool isMatrimony(const Person* firstPerson, const Person* secondPerson) const
         throw(GenealogyTreeException, NullPointerException);

    TreeIterator<const Person* >* getIterator();

    GenealogyTree* getSibs(const Person* person);

    int getState(const Person* person)
		throw(GenealogyTreeException, NullPointerException);

    int getState(const Person* first, const Person* second)
		throw(GenealogyTreeException, NullPointerException);

    std::list<const Person *>* findAll(const Person* person) const;

    friend std::ostream& operator<<(std::ostream& os, const GenealogyTree& tree);
    friend std::istream& operator>>(std::istream& is, GenealogyTree& tree);
};

}
}

#endif	/* _GENEALOGYTREE_H */

